﻿#include "pch.h"
#include <mmsystem.h>
#include "Game.h"
#include "Resource.h"

/**
 * 构造方法。
 * @param callback  回调
 * @param drawer    绘图者
 * @param gameBoard 游戏区域
 */
Game::Game(CWnd* callback, CDC* drawer, CWnd* gameBoard) :
    mApple(NULL),
    mCallback(callback),
    mDifficulty(1),
    mDrawer(drawer),
    mEnableMusic(FALSE),
    mGameBoard(gameBoard),
    mScore(0),
    mSnake(NULL),
    mStatus(END) {
    // 重绘游戏区域
    this->DrawGameBoard();

    // 置随机数种子
    srand((UINT)time(NULL));
}

/**
 * 在随机位置创建果子。
 */
void Game::CreateApple() {
    CPoint point;
    BOOL used = FALSE;

    // 创建果子
    do {
        // 取 x、y 的随机值
        point.x = (rand() % (Const::GAME_BOARD_GRID_COUNT_H - 2) + 1);
        point.y = (rand() % (Const::GAME_BOARD_GRID_COUNT_V - 2) + 1);
        used = this->PointIsUsed(&point);
    } while (used);
    mApple = new SnakeBody(mDrawer, &point, SnakeBody::APPLE);
}

/**
 * 画游戏区域。
 */
void Game::DrawGameBoard() {
    mDrawer->FillSolidRect(0, 0, Const::GAME_BOARD_WIDTH, Const::GAME_BOARD_HEIGHT, Const::GAME_BOARD_COLOR);
}

/**
 * 游戏结束。
 * @param isWon 胜利则为 TRUE，否则为 FALSE
 */
void Game::GameOver(BOOL isWon) {
    // 将状态设置为已结束
    mStatus = END;

    // 停止定时器
    mCallback->KillTimer(Const::TIMER_ID);

    // 停止播放音乐
    if (mEnableMusic) {
        PlaySound(NULL, NULL, NULL);
    }

    // 发送通知
    mCallback->SendMessage(Const::UM_GAME_OVER, isWon);
}

/**
 * 获取游戏状态。
 * @return 游戏状态
 */
Game::Status Game::GetStatus() {
    return mStatus;
}

/**
 * 判断是否胜利。
 * @return 胜利则返回 TRUE，否则返回 FALSE
 */
BOOL Game::IsWon() {
    return mScore >= Const::WIN_NUMBER;
}

/**
 * 按键事件的响应方法。
 * @param key   按键
 */
void Game::OnKeyPressed(UINT key) {
    if (mStatus != PLAYING) {
        return;
    }
    if (key >= VK_LEFT && key <= VK_DOWN) {
        mSnake->Turn(key);
    }
}

/**
 * 定时器事件的响应方法。
 */
void Game::OnTimer() {
    // 移动蛇
    BOOL isDead = mSnake->Move();
    if (isDead) {
        this->GameOver(FALSE);
        return;
    }

    // 检查是否碰到果子
    SnakeBody* head = mSnake->GetHead();
    if (*head->GetPosition() == *mApple->GetPosition()) {
        // 碰到果子，将果子加入蛇链表
        mSnake->Eat(mApple);
        this->CreateApple();
        mScore++;
        mCallback->SendMessage(Const::UM_SCORE, mScore);

        // 判断是否胜利
        if (this->IsWon()) {
            this->GameOver(TRUE);
            return;
        }

        // 判断是否达到增加难度的条件
        if (mScore % Const::DIFF_BASE == 0 && mDifficulty != Const::DIFF_MAX) {
            mDifficulty++;
            mCallback->SendMessage(Const::UM_DIFFICULTY_UP, mDifficulty);
            mCallback->KillTimer(Const::TIMER_ID);
            UINT elapse = Const::TIMER_INIT - Const::TIMER_GROW * (mDifficulty - 1);
            mCallback->SetTimer(Const::TIMER_ID, elapse, NULL);
        }
    }

    // 通知游戏区域重绘
    mGameBoard->Invalidate(FALSE);
}

/**
 * 游戏暂停。
 */
void Game::Pause() {
    if (mStatus == PLAYING) {
        // 停止定时器
        mCallback->KillTimer(Const::TIMER_ID);

        // 停止播放音乐
        if (mEnableMusic) {
            PlaySound(NULL, NULL, NULL);
        }

        // 将状态设置为已暂停
        mStatus = PAUSED;
    } else if (mStatus == PAUSED) {
        // 开启定时器
        mCallback->SetTimer(Const::TIMER_ID, Const::TIMER_INIT - Const::TIMER_GROW * (mDifficulty - 1), NULL);

        // 播放音乐
        if (mEnableMusic) {
            PlaySound(MAKEINTRESOURCE(IDR_MUSIC), NULL, SND_RESOURCE | SND_ASYNC | SND_NODEFAULT | SND_LOOP);
        }

        // 将状态设置为游戏中
        mStatus = PLAYING;
    }
}

/**
 * 播放音乐。
 * @return 正在播放音乐则为 TRUE，否则为 FALSE
 */
BOOL Game::PlayMusic() {
    mEnableMusic = !mEnableMusic;

    if (mEnableMusic) {
        if (mStatus == PLAYING) {
            PlaySound(MAKEINTRESOURCE(IDR_MUSIC), NULL, SND_RESOURCE | SND_ASYNC | SND_NODEFAULT | SND_LOOP);
        }
    } else {
        PlaySound(NULL, NULL, NULL);
    }

    return mEnableMusic;
}

/**
 * 判断某个点是否被占用。
 * @param point 点
 * @return 被占用了则返回 TRUE，否则返回 FALSE
 */
BOOL Game::PointIsUsed(CPoint* point) {
    // 检查点是否在蛇上
    if (mSnake != NULL) {
        if (mSnake->PointIsOnMe(point)) {
            return TRUE;
        }
    }

    // 检查点是否在果子上
    if (mApple != NULL) {
        return *point == *mApple->GetPosition();
    }

    return FALSE;
}

/**
 * 游戏开始。
 */
void Game::Start() {
    // 重绘游戏区域
    this->DrawGameBoard();

    // 创建蛇
    if (mSnake != NULL) {
        delete mSnake;
    }
    mSnake = new Snake(mDrawer);

    // 创建果子
    if (mApple != NULL) {
        delete mApple;
    }
    this->CreateApple();

    // 通知游戏区域重绘
    mGameBoard->Invalidate(FALSE);

    // 重置难度
    mDifficulty = 1;

    // 重置分数
    mScore = 0;

    // 开启定时器
    mCallback->KillTimer(Const::TIMER_ID);
    mCallback->SetTimer(Const::TIMER_ID, Const::TIMER_INIT, NULL);

    // 播放音乐
    if (mEnableMusic) {
        PlaySound(MAKEINTRESOURCE(IDR_MUSIC), NULL, SND_RESOURCE | SND_ASYNC | SND_NODEFAULT | SND_LOOP);
    }

    // 将状态设置为游戏中
    mStatus = PLAYING;
}
